/*
	Copyright 2009 Benjamin Vedder	vedder87@gmail.com
	
	This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */

package com.google.code.retrobox.editor.sprites;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EtchedBorder;

import com.google.code.retrobox.editor.commons.ColorButton;
import com.google.code.retrobox.editor.commons.Tools;
import com.google.code.retrobox.editor.commons.dialog.ColorReplaceDialog;

public class SpriteEditor extends JPanel implements ActionListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static final int SPRITES_PER_SET = 8;
	
	private JFrame parent = null;
		
	private ColorReplaceDialog replaceDialog;
	
	private List<SpriteRenderer> renderers = new ArrayList<SpriteRenderer>();
	
	// Components
	private JPanel tool1Panel = new JPanel(new BorderLayout());
	private JPanel tool2Panel = new JPanel(new BorderLayout());
	
	private JPanel colorBar = new JPanel(new GridLayout(2, 8));
	private JPanel currentColor = new JPanel();
	
	private JPanel spritePanel = null;

	private JButton replaceColorButton = new JButton("Replace all colors...");
	private JButton previewButton = new JButton("Preview");
	private JButton flipXButton = new JButton("Flip Horizontal");
	private JButton flipYButton = new JButton("Flip Vertical");
	private JButton copyButton = new JButton("Copy sprite");
	private JButton pasteButton = new JButton("Paste sprite");
	private JButton exportButton = new JButton("Export sprite");
	
	private JButton playButton = new JButton("Play");
	private JButton stopButton = new JButton("Stop");
	private JButton nextButton = new JButton("Next");
	private JButton prevButton = new JButton("Prev");
	private JButton saveAllButton = new JButton("Save all");
	
	private ButtonGroup currentButtonGroup = new ButtonGroup();
	
	private int currentIndex = 0;
	
	private JImagePanel previewImagePanel;
	
	private char[] pixelData = null; 
	
	public SpriteEditor(JFrame parent) {
		this.parent = parent;
		
		init();
	}
	
	private void init() {
		//TODO: cleanup code
		spritePanel = new JPanel(new GridLayout(2, SPRITES_PER_SET / 2));
		spritePanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Frames"));
		setLayout(new BorderLayout());
		
		replaceColorButton.addActionListener(this);
		previewButton.addActionListener(this);
		playButton.addActionListener(this);
		stopButton.addActionListener(this);
		nextButton.addActionListener(this);
		prevButton.addActionListener(this);
		flipXButton.addActionListener(this);
		flipYButton.addActionListener(this);
		copyButton.addActionListener(this);
		pasteButton.addActionListener(this);
		exportButton.addActionListener(this);
		saveAllButton.addActionListener(this);
		
		for (int i = 0;i < 16;i++) {
			ColorButton b = new ColorButton();
			b.setOpaque(true);
			b.setBackground(Tools.getColor(i));
			b.setPreferredSize(new Dimension(32, 32));
			
			b.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					ColorButton b = (ColorButton)arg0.getSource();
					currentColor.setBackground(b.getBackground());
				}
			});
			
			colorBar.add(b);
		}
		
		tool1Panel.add(colorBar, BorderLayout.CENTER);
		
		JPanel tmpPanel = new JPanel(new BorderLayout());
		tmpPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
		
		currentColor.setOpaque(true);
		currentColor.setBackground(Tools.getColor(0));
		currentColor.setPreferredSize(new Dimension(80, 80));
		tmpPanel.add(currentColor, BorderLayout.CENTER);
		
		tool1Panel.add(tmpPanel, BorderLayout.EAST);
		
		JPanel toolsPanel = new JPanel(new GridLayout(7,1));
		toolsPanel.add(replaceColorButton);
		toolsPanel.add(previewButton);
		toolsPanel.add(flipXButton);
		toolsPanel.add(flipYButton);
		toolsPanel.add(copyButton);
		toolsPanel.add(pasteButton);
		toolsPanel.add(exportButton);
		tool2Panel.add(toolsPanel,BorderLayout.NORTH);
		
		tool1Panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Palette"));
		tool2Panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Tools"));
		/*Add SpriteRenderers */
		for (int i = 0;i < SPRITES_PER_SET;i++) {
			JPanel singleSprite = new JPanel(new BorderLayout());
			JRadioButton currentButton = new JRadioButton();
			currentButtonGroup.add(currentButton);
			if (i == 0) {
				currentButton.setSelected(true);
			}
			final int ci = i;
			currentButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					currentIndex = ci;
				}
			});
			final JLabel indexLabel = new JLabel("#" + i);
			JPanel tmp2 = new JPanel(new BorderLayout());
			tmp2.add(indexLabel, BorderLayout.CENTER);
			tmp2.add(currentButton, BorderLayout.WEST);
			
			SpriteRenderer rend = new SpriteRenderer(this);
			rend.setMaximumSize(new Dimension(16*6,16*6));
			rend.setMinimumSize(new Dimension(16*6,16*6));
			

			
			if (i < SPRITES_PER_SET  / 2) {
				singleSprite.add(tmp2, BorderLayout.NORTH);
				singleSprite.add(rend, BorderLayout.CENTER);
			} else {
				singleSprite.add(tmp2, BorderLayout.SOUTH);
				singleSprite.add(rend, BorderLayout.CENTER);
			}
			
			singleSprite.setBorder(BorderFactory.createEtchedBorder());
			
			spritePanel.add(singleSprite);
			renderers.add(rend);
		}
		
		JPanel tmp = new JPanel(new BorderLayout());
		
		
		JPanel tmp2 = new JPanel(new BorderLayout());
		
		JPanel spriteAnimPanel = new JPanel(new GridLayout(4,1));
		JPanel tmp3 = new JPanel(new GridLayout(2,1));
		
		spriteAnimPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Preview"));
		
		previewImagePanel = new JImagePanel(getSpriteImages(3),0,0);
		previewImagePanel.setSize(100, 100);
		tmp3.add(previewImagePanel);
		JPanel spriteAnimButtonBarPanel = new JPanel(new GridLayout(1,4));
		spriteAnimButtonBarPanel.add(playButton);
		spriteAnimButtonBarPanel.add(stopButton);
		spriteAnimButtonBarPanel.add(nextButton);
		spriteAnimButtonBarPanel.add(prevButton);
		tmp3.add(spriteAnimButtonBarPanel);
		spriteAnimPanel.add(tmp3);
		tmp2.add(spriteAnimPanel,BorderLayout.CENTER);
		JPanel spritePanelWrapper = new JPanel(new BorderLayout());
		spritePanelWrapper.add(spritePanel,BorderLayout.NORTH);
		spritePanelWrapper.add(new JPanel(new BorderLayout()),BorderLayout.CENTER);
		tmp.add(spritePanelWrapper, BorderLayout.CENTER);
		tmp.add(tmp2,BorderLayout.EAST);
		add(tmp, BorderLayout.CENTER);
		add(tool1Panel, BorderLayout.SOUTH);
		add(tool2Panel, BorderLayout.EAST);
	}
	
	public BufferedImage[] getSpriteImages(int scale){
		BufferedImage[] buffer = new BufferedImage[8];
		for(int t=0;t<8;t++){
			buffer[t] = renderers.get(t).getBufferedImage(3);
		}
		return buffer;
	}
	
	public void replaceColor(Color oldColor, Color newColor) {
		// TODO!
		
		if (parent != null) {
			parent.validate();
		}
		repaint();
	}
	
	public Color getCurrentColor() {
		return currentColor.getBackground();
	}
	
	public void setCurrentColor(Color c) {
		currentColor.setBackground(c);
	}
	
	public void setSprite(char[] sp) {
		int ind = 0, ind2 = 0;
		
		int pic = (SpriteRenderer.SPRITES_X * SpriteRenderer.SPRITES_Y) / 2;
		char[] tmp = new char[pic];
		
		for (char element: sp) {
			if (ind == pic) {
				ind = 0;
				
				if (ind2 < renderers.size()) {
					renderers.get(ind2).setSprite(tmp);
				}
				
				ind2++;
				tmp = new char[pic];
			}
			
			tmp[ind] = element;
			
			ind++;
		}
		
		// Add the last sprite.
		if (ind2 < renderers.size()) {
			renderers.get(ind2).setSprite(tmp);
		}
		/* update the preview panel */
		this.previewImagePanel.stopAnimation();
		this.previewImagePanel.setImages(this.getSpriteImages(3));
	}
	
	public char[] getRawData() {
		List<Character> data = new ArrayList<Character>();
		
		for (SpriteRenderer element: renderers) {
			char[] tmp = element.getSprite();
			
			boolean add = false;
			char a = tmp[0];
			for (char element2: tmp) {
				if (element2 != a) {
					add = true;
				}
			}
			
			if (add) {
				for (char element2: tmp) {
					data.add(element2);
				}
			}
		}
		
		char[] array = new char[data.size()];
		for (int i = 0;i < data.size();i++) {
			array[i] = data.get(i);
		}
		
		return array;
	}

	public char[] getRawDataAsByteArray() {
		List<Character> data = new ArrayList<Character>();
		
		for (SpriteRenderer element: renderers) {
			char[] tmp = element.getSpriteByteArray();
			
			boolean add = false;
			char a = tmp[0];
			for (char element2: tmp) {
				if (element2 != a) {
					add = true;
				}
			}
			
			if (add) {
				for (char element2: tmp) {
					data.add(element2);
				}
			}
		}
		
		char[] array = new char[data.size()];
		for (int i = 0;i < data.size();i++) {
			array[i] = data.get(i);
		}
		
		return array;
	}	

	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == replaceColorButton) {
			replaceDialog = new ColorReplaceDialog(parent);
			replaceDialog.addActionListener(this);
			
		} else if (e.getSource() == replaceDialog) {
			replaceColor(replaceDialog.getOldColor(), replaceDialog.getNewColor());
		} else if (e.getSource() == previewButton) {
			this.previewImagePanel.setImages(getSpriteImages(3));
		}else if (e.getSource() == playButton) {
			this.previewImagePanel.startAnimation();
		}else if (e.getSource() == stopButton) {
			this.previewImagePanel.stopAnimation();
		}else if (e.getSource() == nextButton) {
			this.previewImagePanel.nextSprite();
		}else if (e.getSource() == prevButton) {
			this.previewImagePanel.prevSprite();
		}else if (e.getSource() == flipXButton) {
			this.renderers.get(currentIndex).flipSpriteX();
		}else if (e.getSource() == flipYButton) {
			this.renderers.get(currentIndex).flipSpriteY();
		}else if (e.getSource() == copyButton) {
			this.pixelData = this.renderers.get(currentIndex).getSprite();
		}else if (e.getSource() == pasteButton) {
			if(this.pixelData != null){
			this.renderers.get(currentIndex).setSprite(this.pixelData.clone());
			}
		}else if (e.getSource() == exportButton) {
			JFileChooser fc = new JFileChooser(); 
			int returnVal = fc.showSaveDialog(this);

			File file;

			if (returnVal == JFileChooser.APPROVE_OPTION) {
				file = fc.getSelectedFile();
			} else {
				return;
			}

			if (file.exists()) {
				if (!(JOptionPane.showConfirmDialog(this,
						"Overwrite existing file?") == JOptionPane.OK_OPTION)) {
					return;
				}
			}

			try {

				String format = "png";  
		        ImageIO.write(this.renderers.get(currentIndex).getBufferedImage(1), format, file);  
				JOptionPane
						.showMessageDialog(
								this,
								"<html>"
										+ "Sprite header file has been written to <br><font color=green>"
										+ file.getAbsolutePath()
										+ "</font color=green></html>");

			} catch (Exception ex) {
				JOptionPane.showMessageDialog(this, "<html>"
						+ "Error saving Sprite <br><font color=green>"
						+ ex.getLocalizedMessage() + "</font color=green></html>");
			}
		}
	}
}








